package com.sugar.queryinfo.module.business.api.bi.core;

import cn.hutool.core.io.IORuntimeException;
import cn.hutool.core.lang.TypeReference;
import cn.hutool.core.util.HexUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.sugar.queryinfo.framework.common.exception.ServiceException;
import com.sugar.queryinfo.module.business.api.bi.core.dto.ApiReqVO;
import com.sugar.queryinfo.module.business.api.bi.core.dto.ApiRespVO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

import java.lang.reflect.Type;
import java.nio.charset.StandardCharsets;
import java.security.spec.AlgorithmParameterSpec;
import java.util.Base64;
import java.util.List;

import static com.sugar.queryinfo.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.sugar.queryinfo.module.business.api.bi.core.BackInvestBasicApiEnum.API_SECRET_KEY;
import static com.sugar.queryinfo.module.business.api.bi.core.BackInvestBasicApiEnum.API_SUCCESS_CODE;
import static com.sugar.queryinfo.module.business.enums.ErrorCodeConstants.*;

/**
 * @author Y.sugar
 * @since 2025/3/8 14:47
 */
public interface BackInvestBasicApi {

    Logger LOG = LoggerFactory.getLogger(BackInvestBasicApi.class);

    /**
     * 执行调用接口
     *
     * @param backInvestBasicApiEnum Api接口枚举
     * @return 接口返回数据
     */
    default <ReqT extends ApiReqVO> String doApi(BackInvestBasicApiEnum backInvestBasicApiEnum, ReqT reqVO) {
        return doApi(backInvestBasicApiEnum.buildReq(reqVO));
    }

    /**
     * 执行调用接口
     *
     * @param backInvestBasicApiEnum Api接口枚举
     * @param cls               期望的数据类型
     * @param <T>               期望的数据类型
     * @return 接口返回数据
     */
    default <T, ReqT extends ApiReqVO> T doApi(BackInvestBasicApiEnum backInvestBasicApiEnum, ReqT reqVO, Class<T> cls) {
        return doApi(backInvestBasicApiEnum.buildReq(reqVO), cls);
    }

    /**
     * 执行调用接口
     *
     * @param request Api请求对象
     * @return 接口返回数据
     */
    default String doApi(HttpRequest request) {
        return doApi(request, String.class);
    }

    /**
     * 执行调用接口
     *
     * @param request Api请求对象
     * @param cls     期望的数据类型
     * @param <T>     期望的数据类型
     * @return 接口返回数据
     */
    default <T> T doApi(HttpRequest request, Class<T> cls) {
        try (HttpResponse resp = request.execute()) {
            int status = resp.getStatus();
            String body = resp.body();
            LOG.info("调用 智能背调 【{}】 接口, 返回 【{}】", request.getUrl(), body);
            if (200 == status) {
                // 判断待转换类型是否为 String
                /*if (cls.equals(String.class))
                    return cls.cast(body);*/

                // 转换 json字符串为指定对象
                ApiRespVO<T> apiRespVO = JSONUtil.toBean(body, new TypeReference<ApiRespVO<T>>(){
                    @Override
                    public Type getType() {
                        return ParameterizedTypeImpl.make(ApiRespVO.class, new Type[]{cls}, null);
                    }
                }, false);

                String code = apiRespVO.getCode();
                if ("201".equals(code)/* || "311".equals(code)*/) {
                    return null;
                }

                if (Boolean.FALSE.equals(apiRespVO.getSuccess()) || !API_SUCCESS_CODE.equals(code))
                    throw exception(BACK_INVEST_API_INVOKE_EXCEPTION, apiRespVO.getMessage());

                return apiRespVO.getData();
            } else
                throw exception(BACK_INVEST_API_INVOKE_FAIL);
        } catch (ServiceException e) {
            throw e;
        } catch (IORuntimeException e) {
            throw exception(BACK_INVEST_API_INVOKE_TIMEOUT);
        } catch (Throwable e) {
            LOG.error("【智能背调 接口调用失败：{}】 - 失败详情：", e.getMessage(), e);
            throw exception(BACK_INVEST_API_INVOKE_FAIL);
        }
    }

    /**
     * 执行调用接口
     *
     * @param backInvestBasicApiEnum Api接口枚举
     * @param cls               期望的数据类型
     * @param <T>               期望的数据类型
     * @return 接口返回数据
     */
    default <T, ReqT extends ApiReqVO> List<T> doApiList(BackInvestBasicApiEnum backInvestBasicApiEnum, ReqT reqVO, Class<T> cls) {
        return doApiList(backInvestBasicApiEnum.buildReq(reqVO), cls);
    }

    /**
     * 执行调用接口
     *
     * @param request Api请求对象
     * @param cls     期望的数据类型
     * @param <T>     期望的数据类型
     * @return 接口返回数据
     */
    default <T> List<T> doApiList(HttpRequest request, Class<T> cls) {
        try (HttpResponse resp = request.execute()) {
            int status = resp.getStatus();
            String body = resp.body();
            LOG.info("调用 智能背调 【{}】 接口, 返回 【{}】", request.getUrl(), body);
            if (200 == status) {
                // 转换 json字符串为指定对象
                JSONObject respJson = JSONUtil.parseObj(body);

                String code = respJson.getStr("code");
                if ("201".equals(code)/* || "311".equals(code)*/) {
                    return null;
                }

                if (Boolean.FALSE.equals(respJson.getBool("success")) || !API_SUCCESS_CODE.equals(code))
                    throw exception(BACK_INVEST_API_INVOKE_EXCEPTION, respJson.getStr("message"));

                return respJson.getBeanList("data", cls);
            } else
                throw exception(BACK_INVEST_API_INVOKE_FAIL);
        } catch (ServiceException e) {
            throw e;
        } catch (IORuntimeException e) {
            throw exception(BACK_INVEST_API_INVOKE_TIMEOUT);
        } catch (Throwable e) {
            LOG.error("【智能背调 接口调用失败：{}】 - 失败详情：", e.getMessage(), e);
            throw exception(BACK_INVEST_API_INVOKE_FAIL);
        }
    }

    static String encrypt(String data) {
        try {
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
            SecretKeySpec keySpec = new SecretKeySpec(HexUtil.decodeHex(API_SECRET_KEY), "AES");
            AlgorithmParameterSpec paramSpec = new IvParameterSpec(API_SECRET_KEY.substring(0, 16).getBytes(StandardCharsets.UTF_8));
            cipher.init(1, keySpec, paramSpec);
            byte[] result = cipher.doFinal(data.getBytes(StandardCharsets.UTF_8));
            return Base64.getEncoder().encodeToString(result);
        } catch (Throwable e) {
            LOG.error("接口加密失败：", e);
            throw exception(BACK_INVEST_API_INVOKE_FAIL);
        }
    }

    static String decrypt(String data) {
        try {
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
            SecretKeySpec keySpec = new SecretKeySpec(HexUtil.decodeHex(API_SECRET_KEY), "AES");
            AlgorithmParameterSpec paramSpec = new IvParameterSpec(API_SECRET_KEY.substring(0, 16).getBytes(StandardCharsets.UTF_8));
            cipher.init(2, keySpec, paramSpec);
            return new String(cipher.doFinal(Base64.getMimeDecoder().decode(data)), StandardCharsets.UTF_8);
        } catch (Throwable e) {
            LOG.error("接口解密失败：", e);
            throw exception(BACK_INVEST_API_INVOKE_FAIL);
        }
    }
}
